mod error;

use jsonrpsee::{
    common::{
        to_value as to_json_value,
        Params,
    },
    Client,
};

use sp_rpc::{
    list::ListOrValue,
    number::NumberOrHex,
};

pub struct Rpc {
    client: Client,
}

use error::Error;

impl Rpc {
    pub fn new(client: Client) -> Self {
        Self {
            client,
        }
    }

    /// Fetch the genesis hash
    pub async fn genesis_hash(&self) -> Result<Vec<u8>, Error> {
        let block_zero = Some(ListOrValue::Value(NumberOrHex::Number(0)));
        let params = Params::Array(vec![to_json_value(block_zero)?]);
        let list_or_value: ListOrValue<Option<Vec<u8>>> =
            self.client.request("chain_getBlockHash", params).await?;
        match list_or_value {
            ListOrValue::Value(genesis_hash) => {
                genesis_hash.ok_or_else(|| "Genesis hash not found".into())
            }
            ListOrValue::List(_) => Err("Expected a Value, got a List".into()),
        }
    }

    /// Fetch the metadata
    pub async fn metadata(&self) -> Result<Vec<u8>, Error> {
        let bytes: Vec<u8> = self
            .client
            .request("state_getMetadata", Params::None)
            .await?;
//        let meta: RuntimeMetadataPrefixed = Decode::decode(&mut &bytes[..])?;
//        let metadata: Metadata = meta.try_into()?;
        Ok(bytes)
    }
}

jsonrpsee::rpc_api! {
    Health {
        /// Test
        fn system_name(foo: String, bar: i32) -> String;

        fn test_notif(foo: String, bar: i32);

        /// Test2
        #[rpc(method = "foo")]
        fn system_name2() -> String;
    }

    System {
        fn test_foo() -> String;
    }
}

#[async_std::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    env_logger::init();

    let client =jsonrpsee::ws_client("ws://192.168.2.206:9944").await?;
    let rpc = Rpc::new(client);
    let res = rpc.metadata().await;

    println!("{:?}", res);

    Ok(())
}